package common.dao.elastic;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.api.client.json.Json;
import org.bson.Document;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequestBuilder;
import org.elasticsearch.client.Client;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/*
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
*/
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestFactory;
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.HttpResponse;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.InputStreamContent;
import com.google.api.client.http.javanet.NetHttpTransport;
import common.helper.toolkit.FileToolkit;
import common.helper.toolkit.HttpToolkit;
import common.helper.json.JsonToJavaObject;
//import com.google.restapi.client.json.JsonFactory;
//import com.google.restapi.client.json.JsonObjectParser;
//import com.google.restapi.client.json.jackson2.JacksonFactory;

public class ElasticAdministratorHttpHelper {

	public static final Logger logger = LoggerFactory.getLogger(ElasticAdministratorHttpHelper.class);
	//public static final ObjectMapper mapper = new ObjectMapper();
	public static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
	//public static final JsonFactory JSON_FACTORY = new JacksonFactory();
	public static  String clutser_name = "elasticsearch_cluster";

	/*
	*************************** main ****************************
	 */
	public static void main(String[] args){
		//ElasticAdministratorHttpHelper.putMongodbRiver("/elastic_admin/http_servers.json", "/mongodb_rivers/");
		//ElasticAdministratorHttpHelper.setMongoRivers("/elastic_admin/http_servers.json", "/mongodb_rivers/");
		String index_name = "testindex";
		String host_path = "/elastic_admin/http_servers.json";
		/*
		boolean ret4 = deleteIndex(index_name,host_path);
		logger.debug("delete index ret = {}\n\n", ret4);
		waitSeconds(3);
		boolean ret5 = createIndex(index_name,host_path, "/elastic_admin/_settings.json");
		logger.debug("create index ret = {}\n\n", ret5);
		waitSeconds(3);
		boolean ret1 = closeIndex(index_name ,host_path );
		logger.debug("close index ret = {}\n\n", ret1);
		waitSeconds(3);
		boolean ret2 = settingAnalysis(index_name, host_path, "/elasticsearch/analysis.json");
		logger.debug("set index ret = {}\n\n", ret2);
		waitSeconds(3);
		boolean ret3 = openIndex(index_name ,host_path );
		logger.debug("open index ret = {}\n\n", ret3);
		//boolean ret6 = deleteIndex(index_name,host_path);
		//logger.debug("delete index ret = {}\n\n", ret6);
		waitSeconds(3);
		String[] collections = {"program" , "sequence" , "scene", "shot"};
		boolean ret8 = settingMapiings(index_name,collections,host_path,"/elasticsearch/video.json");
		logger.debug("setting mappins ret = {}\n\n", ret8);

		boolean ret6 = deleteIndex(index_name,host_path);
		logger.debug("delete index ret = {}\n\n", ret6);
		*/
	}
	/*************************************************************/



	/**************************************************************
	 *
	 * @param output
	 * @return
	 */
	private static boolean parseOutput(String output){
		JsonNode retNode = JsonToJavaObject.loadJsonNode(output);
		JsonNode err_node = retNode.get("error");
		if (err_node != null)
			return false;
		JsonNode ack_node = retNode.get("acknowledged");
		if (ack_node == null)
			return false;
		boolean ret_code = ack_node.asBoolean(false);
		return ret_code;
	}

	/**********************************************************
	 *
	 * @param indexName
	 * @param hostPath
	 * @param jsonPath
	 * @return
	 */
	public static boolean createIndex(String indexName, String hostPath, String jsonPath){
		String url = HttpToolkit.getHostPort(hostPath);
		url += indexName;
		String input = FileToolkit.readStringFromFile(jsonPath);
		String output = HttpToolkit.rest_put(url, input);
		logger.debug("Create Index Output \n {}", output);
		return parseOutput(output);
	}

	/************************************************************
	 *
	 * @param indexName
	 * @param hostPath
	 * @return
	 */
	public static boolean deleteIndex(String indexName, String hostPath){
		String url = HttpToolkit.getHostPort(hostPath);
		url += indexName;
		String output = HttpToolkit.rest_del(url);
		logger.debug("Delete Index Output \n {}", output);
		return parseOutput(output);
	}

	/**************************************************************
	 *
	 * @param indexName
	 * @param hostPath
	 * @return
	 */
	public static boolean closeIndex(String indexName, String hostPath){
		String url = HttpToolkit.getHostPort(hostPath);
		url += (indexName + "/_close");
		String output = HttpToolkit.rest_post(url, "");
		logger.debug("Close Index Output \n {}", output);
		return parseOutput(output);
	}

	/******************************************************************
	 *
	 * @param indexName
	 * @param hostPath
	 * @return
	 */
	public static boolean openIndex(String indexName, String hostPath){
		String url = HttpToolkit.getHostPort(hostPath);
		url += (indexName + "/_open");
		String output = HttpToolkit.rest_post(url, "");
		logger.debug("Open Index Output \n {}", output);
		return parseOutput(output);
	}


	public static boolean is_index_open(String index){
		/*
		http://stackoverflow.com/questions/21917474/how-do-i-get-a-list-of-closed-indexes-in-elasticsearch
		 */
		return true;
	}

	/***************************************************************
	 *
	 * @param indexName
	 * @param hostPath
	 * @param jsonPath
	 * @return
	 */
	public static boolean settingAnalysis(String indexName, String hostPath, String jsonPath){
		String url = HttpToolkit.getHostPort(hostPath);
		url += (indexName + "/_settings");
		String input = FileToolkit.readStringFromFile(jsonPath);
		String output = HttpToolkit.rest_put(url, input);
		logger.debug("[settingAnalysis] Setting Analysis Output \n {}", output);
		return parseOutput(output);
	}

	/****************************************************************
	 *
	 * @param indexName
	 * @param collection
	 * @param hostPath
	 * @param jsonPath
	 * @return
	 */
	public static boolean settingVideoMapping(String indexName, String collection, String hostPath, String jsonPath){
		String json = FileToolkit.readStringFromFile(jsonPath);
		JsonNode rootNode = JsonToJavaObject.loadJsonNode(json);
		JsonToJavaObject.printJsonNode(rootNode);
		JsonFactory factory = new JsonFactory();
		ObjectMapper mapper = new ObjectMapper(factory);
		JsonNode inputNode = mapper.createObjectNode();
		((ObjectNode)inputNode).put(collection , rootNode.get("video"));
		return settingColMappingByJSON(indexName,collection,hostPath,inputNode);
	}

	public static boolean settingCollectionMapping(String indexName, String collection, String hostPath, String jsonPath){
		String json = FileToolkit.readStringFromFile(jsonPath);
		JsonNode rootNode = JsonToJavaObject.loadJsonNode(json);
		JsonToJavaObject.printJsonNode(rootNode);
		JsonFactory factory = new JsonFactory();
		ObjectMapper mapper = new ObjectMapper(factory);
		JsonNode inputNode = mapper.createObjectNode();
		((ObjectNode)inputNode).put(collection , rootNode.get("video"));
		/*
		Parent-Child不好用
		 */
		/*
		JsonNode parNode = mapper.createObjectNode();
		((ObjectNode)parNode).put("type", IndexTypeNames.VideoDB.getVideoTypeName());
		JsonNode colNode = inputNode.get(collection);
		((ObjectNode)colNode).put("_parent" , parNode);
		*/
		return settingColMappingByJSON(indexName,collection,hostPath,inputNode);
	}

	private static boolean settingColMappingByJSON(String indexName, String collection, String hostPath, JsonNode inputNode){
		String url = HttpToolkit.getHostPort(hostPath);
		url += (indexName + "/_mapping/" + collection);
		String input = JsonToJavaObject.jsonNodeToString(inputNode);
		JsonToJavaObject.printJsonNode(inputNode);
		String output = HttpToolkit.rest_put(url, input);
		logger.debug("Setting Mapping Output \n {}", output);
		return parseOutput(output);
	}

	/****************************************************************
	 *
	 * @param indexName
	 * @param collections
	 * @param hostPath
	 * @param jsonPath
	 * @return
	 */
	public static boolean settingMapiings(String indexName, String[] collections, String hostPath, String jsonPath){
		boolean ret = true;
		for(String col : collections){
			if(settingCollectionMapping(indexName,col,hostPath,jsonPath) == false)
				ret = false;
		}
		return ret;
	}

	/*
	***************************************
	set Index Aliases
	***************************************
	 */
	public static void setAliases(Client esClient, String filePath){
		String json = FileToolkit.readStringFromFile(filePath);
		logger.debug("Aliases : \n {}",json);
		IndicesAliasesRequestBuilder iaBuilder = esClient.admin().indices().prepareAliases();
		//org.bson
		// http://api.mongodb.org/java/current/org/bson/package-summary.html
		// http://api.mongodb.org/java/current/org/bson/Document.html
		Document bson = Document.parse(json);
		//System.out.println(bson.toJson());
		//BsonArray actions = (BsonArray) bson.get("actions");
		//java.lang.ClassCastException: java.util.ArrayList cannot be cast to org.bson.BsonArray
		List<Document> actions = (List<Document>) bson.get("actions");
		for(Document action : actions) {
			if(action.containsKey("remove")){
				Document remove = (Document) action.get("remove");
				String index = remove.getString("index");
				String alias = remove.getString("alias");
				if(!(index==null) && !(alias==null)){
					iaBuilder.removeAlias(index, alias);
				}
			}
			else if(action.containsKey("add")){
				Document add = (Document) action.get("add");
				String index = add.getString("index");
				String alias = add.getString("alias");
				if(!(index==null) && !(alias==null)){
					iaBuilder.addAlias(index, alias);
				}
			}
		}
		//return iaBuilder.execute().actionGet();
	}


	/*************************************************************************
	 *
	 * @param hostPath
	 * @param jsonPath
	 * @return
	 */
	public static boolean setMongoRivers(String hostPath, String jsonPath){
		String urlStr = HttpToolkit.getHostPort(hostPath);

		String[] mongo_rivers = {"video", "program", "sequence", "scene", "shot"};

		for(int i = 0; i < mongo_rivers.length; i++) {
			String urlRiver = urlStr + "/_river/mongodb_" + mongo_rivers[i] + "/_meta?pretty=true";
			logger.debug("HttpURL : \n {}", urlRiver);

			String mongo_river = jsonPath + "mongo_" + mongo_rivers[i] + ".json";
			String json = FileToolkit.readStringFromFile(mongo_river);
			logger.debug("HttpRequest : \n {}", json);
			String input = FileToolkit.readStringFromFile(mongo_river);

			String output = HttpToolkit.rest_put(urlRiver, input);

			JsonNode retNode = JsonToJavaObject.loadJsonNode(output);

		}
		return true;

	}

	/*
	 * https://developers.google.com/api-client-library/java/google-http-java-client/samples
	 * https://developers.google.com/api-client-library/java/google-http-java-client/transport
	 */
	private static HttpRequestFactory getHttpRequestFactory() {
		HttpRequestFactory requestFactory =
				HTTP_TRANSPORT.createRequestFactory(new HttpRequestInitializer() {
					@Override
					public void initialize(HttpRequest request) {
						//request.setParser(new JsonObjectParser(JSON_FACTORY));
					}
				});
		return requestFactory;
	}

	private static String getHttpURL(String filePath) {
		String json = FileToolkit.readStringFromFile(filePath);
		logger.debug("HTTP Address : \n {}",json);

		Document bson = Document.parse(json);
		List<Document> servers = (List<Document>) bson.get("servers");

		String urlStr = "";
		for(Document server : servers) {
			String host = server.getString("host");
			Integer port = server.getInteger("port");
			if(host!=null && port!=null){
				urlStr = "http://" + host + ":" + port;
				break;
			}
		}
		//GenericUrl url = new GenericUrl(urlStr);
		return urlStr;
	}

	private static void executeHttp(HttpRequest request){
		HttpResponse response = null;
		try {
			response = request.execute();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		String result = null;
		InputStream is = null;
		try {
			is = response.getContent();
			result = FileToolkit.readStringFromStream(is);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		try {
			response.disconnect();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		logger.debug("HttpResponse : \n {}",result);
	}

	public static void putMongodbRiver(String httpserver,String bodyPath){
		String urlStr = getHttpURL(httpserver);

		String[] mongo_rivers = {"video", "shot" ,"program", "sequence", "scene"};

		for(int i = 0; i < mongo_rivers.length; i++){
			String urlRiver = urlStr + "/_river/mongodb_" + mongo_rivers[i] + "/_meta?pretty=true";
			logger.debug("HttpURL : \n {}",urlRiver);
			GenericUrl url = new GenericUrl(urlRiver);

			String mongo_river = bodyPath + "mongo_" + mongo_rivers[i] + ".json";
			String json = FileToolkit.readStringFromFile(mongo_river);
			logger.debug("HttpRequest : \n {}",json);
			// http://javadoc.google-http-java-client.googlecode.com/hg/1.18.0-rc/com/google/api/client/http/InputStreamContent.html
			InputStream in = FileToolkit.getInputStreamFromFile(mongo_river);
			InputStreamContent content = new InputStreamContent("application/json", in );

			HttpRequestFactory requestFactory = getHttpRequestFactory();
			HttpRequest request = null;
			try {
				request = requestFactory.buildPutRequest(url,content);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			// 先暂时禁用 ， 手动设置river，实施数据的导入
			//executeHttp(request);

			/*
			* 同时建立5个River,似乎会遇到并发问题
			* Mongodb-river 存在缺陷
			 */

		}
	}












	/*********************************************************************************
	 *
	 * ElasticSearch Operations
	 *
	 *********************************************************************************/

	/*
	https://www.elastic.co/guide/en/elasticsearch/reference/2.2/search-request-scroll.html#scroll-search-context
	 */
	public static JsonNode initial_scroll(String host, Integer port, String index, String type, Integer alive_minutes, Integer scroll_size){

		String url = "http://" + host + ":" + port + "/" + index + "/" + type + "/_search?scroll=" + alive_minutes + "m";

		logger.info("[initial_scroll] url = {}" , url);

		//ObjectMapper mapper = new ObjectMapper();
		//ObjectNode input = mapper.createObjectNode();
		//input.put("size", scroll_size);

		String jsonInput =
				"{" +
						"\"size\" : " + scroll_size + "," +
						"\"query\" :  { " +
						"            \"match_all\" :  {}  " +
						"              } ," +
						"\"sort\" : [ \"_doc\" ] " +
				"}";
		logger.debug("[initial_scroll] input = {}", jsonInput);

		String output = HttpToolkit.rest_post(url, jsonInput);

		//logger.debug("[initial_scroll] output = {}", output);

		JsonNode outputNode = JsonToJavaObject.loadJsonNode( output );


		return outputNode;

	}


	public static String parse_scroll_id(JsonNode outputNode){
		return outputNode.get("_scroll_id").asText();
	}

	public static Integer parse_scroll_size(JsonNode outputNode){
		return outputNode.get("hits").get("total").asInt();
	}

	public static Integer parse_cursor_size(JsonNode outputNode){
		return outputNode.get("hits").get("hits").size();
	}

	public static ArrayNode parse_records_array(JsonNode outputNode){
		return (ArrayNode)outputNode.get("hits").get("hits");
	}



	public static JsonNode continue_scroll(String host, Integer port, Integer alive_minutes, String scroll_id){

		String url = "http://" + host + ":" + port + "/_search/scroll";

		logger.info("[continue_scroll] url = {}", url);


		String jsonInput =
				"{" +
						"\"scroll\":\"" + alive_minutes + "m\"," +
						"\"scroll_id\":\"" + scroll_id + "\"" + //"," +
					//	"\"sort\" : [ \"_doc\" ] " +
				"}";

		logger.debug("[continue_scroll] input = \n{}", jsonInput);

		String output = HttpToolkit.rest_post(url, jsonInput);
		//logger.debug("[continue_scroll] output = \n\n\n{}\n\n\n",output);

		JsonNode outputNode = JsonToJavaObject.loadJsonNode( output );

		Integer size = parse_cursor_size(outputNode);
		logger.debug("[continue_scroll] output_size = {}", size );

		return outputNode;


	}



}
